package edu.faytechcc.csc.gui;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 * This class represents a window that allows a user to build a text file that 
 * includes the full path of Alice classes on each individual line in the file. 
 * Users are able to add and remove Alice classes to a visible list. When all 
 * needed classes are added to the list, the user may then choose to create the
 * text file. This window is different from the AliceClassEditorWindow and 
 * could be run as a stand-alone application. 
 * 
 * @author Charles Bryan
 */
public class AliceClassListCreatorWindow extends JPanel
{

    private JList list;
    private JButton addButton;
    private DefaultListModel listModel;
    private JButton removeButton;
    private JButton createFileButton;
    private JMenuBar bar;
    private JMenuItem convertItem;
    
    //hold all of the classes as files with full paths
    private ArrayList<File> files;
    //when the file chooser opens it opens to the last directory
    private File lastLocation;

    /**
     * Creates a new AliceClassListCreatorWindow object. This is a new window
     * different from the AliceClassEditorWindow and could be run as a 
     * stand-alone application. 
     */
    public AliceClassListCreatorWindow()
    {
        files = new ArrayList<File>();
        buildPanel();
    }

    /**
     * Create the GUI and show it. As with all GUI code, this must run
     * on the event-dispatching thread.
     */
    public static void createAndShowGUI()
    {
        //Create and set up the window.
        JFrame frame = new JFrame("Alice Class List Creator");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        AliceClassListCreatorWindow newContentPane = new AliceClassListCreatorWindow();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //create and set up the menu bar
        frame.setJMenuBar(newContentPane.buildMenuBar());

        //Display the window.
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }

    /**
     * Closes this application
     */
    private void killMe()
    {
        SwingUtilities.getWindowAncestor(this).dispose();
    }

    /**
     *  Builds the menu bar on the top of the content pane. Includes one Menu,
     * File, with two options, Create a file and exit. Create Files is disabled
     * as long as the lists of classes (listModel and files) are empty.
     */
    private JMenuBar buildMenuBar()
    {
        bar = new JMenuBar();

        JMenu file = new JMenu("File");
        file.setMnemonic('F');
        convertItem = new JMenuItem("Create File");
        convertItem.setEnabled(false);
        convertItem.setMnemonic('C');
        file.add(convertItem);
        JMenuItem exitItem = new JMenuItem("Exit");
        exitItem.setMnemonic('x');
        file.add(exitItem);

        convertItem.addActionListener(
                new CreateFileButtonActionListener());

        exitItem.addActionListener(
                new ActionListener()
                {

                    @Override
                    public void actionPerformed(ActionEvent e)
                    {
                        killMe();
                    }
                });

        bar.add(file);
        return bar;
    }

    /**
     * Build the panel that displays all of the visible components of this 
     * window. 
     */
    private void buildPanel()
    {
        this.setLayout(new BorderLayout());
        this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        //p1 is used to wrap components in a panel before adding them to the mainPanel
        JPanel p1 = new JPanel(new BorderLayout());
        p1.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));

        listModel = new DefaultListModel();
        list = new JList(listModel); //data has type Object[]
        list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        list.setLayoutOrientation(JList.VERTICAL);
        list.setVisibleRowCount(-1);

        JScrollPane listScroller = new JScrollPane(list);
        listScroller.setPreferredSize(new Dimension(250, 150));

        p1.add(listScroller, BorderLayout.NORTH);
        p1.add(new JLabel(
                "* duplicate alice classes in diferent locations"),
                BorderLayout.CENTER);

        this.add(p1, BorderLayout.NORTH);

        p1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
        removeButton = new JButton("Remove Selected");
        removeButton.setEnabled(false);
        removeButton.addActionListener(new RemoveButtonActionListener());
        p1.add(removeButton, BorderLayout.NORTH);


        addButton = new JButton("Add Classes");
        addButton.addActionListener(new AddButtonActionListener());
        p1.add(addButton);
        this.add(p1, BorderLayout.CENTER);


        p1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
        createFileButton = new JButton("~ Create File ~");
        createFileButton.setEnabled(false);
        createFileButton.addActionListener(new CreateFileButtonActionListener());
        p1.add(createFileButton);

        this.add(p1, BorderLayout.SOUTH);
    }

    /**
     * Opens a file chooser in save mode allowing the user to pick the file 
     * name and location the text file with the Alice class paths will be
     * saved to. If the file exists, the users is given the option of 
     * overwriting it or choosing another file. 
     */
    private void createFile()
    {
        JFileChooser fc = new JFileChooser();
        fc.setFileFilter(
                new FileNameExtensionFilter("Text Files: *.txt", "txt"));
        int returnVal = 
                fc.showSaveDialog(SwingUtilities.getWindowAncestor(this));

        if (returnVal == JFileChooser.APPROVE_OPTION)
        {
            if (fc.getSelectedFile().exists())
            {
                int result = JOptionPane.showConfirmDialog(
                        SwingUtilities.getWindowAncestor(this),
                        "This file exists. Do you want to overwrite it?",
                        "File Exists", JOptionPane.YES_NO_OPTION);
                if (result == JOptionPane.NO_OPTION)
                {
                    return;
                }
            }
            writeFile(fc.getSelectedFile());
            this.killMe();
        }
    }

    /**
     * Writes the Alice Paths to the file. If the File does not end with the 
     * *.txt extension, it is added on. If the files is unable to be written,
     * the user is notified and allowed to try again.
     * 
     * @param save The File that the Alice class paths are to be saved to.
     */
    private void writeFile(File save)
    {
        if (!save.getName().endsWith(".txt"))
        {
            save = new File(save.getPath() + ".txt");
        }

        try
        {
            PrintWriter outFile = new PrintWriter(save);
            for (File f : files)
            {
                outFile.println(f.getPath());
            }
            outFile.flush();
            outFile.close();
        } catch (Exception e)
        {
            JOptionPane.showMessageDialog(null,
                    "An error occured, file not written.", "Error",
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    private class CreateFileButtonActionListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            createFile();
        }
    }

    private class RemoveButtonActionListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            int[] indices = list.getSelectedIndices();

            int half = indices.length / 2;
            int swap;
            for (int index = 0; index < half; index++)
            {
                swap = indices[index];
                indices[index] = indices[indices.length - index - 1];
                indices[indices.length - index - 1] = swap;
            }

            for (int index : indices)
            {
                listModel.remove(index);
                files.remove(index);

                int size = listModel.getSize();

                if (size == 0)
                { //Nobody's left, disable firing.
                    removeButton.setEnabled(false);
                    createFileButton.setEnabled(false);
                    convertItem.setEnabled(false);

                }
                else
                { //Select an index.
                    if (index == listModel.getSize())
                    {
                        //removed item in last position
                        index--;
                    }

                    list.setSelectedIndex(index);
                    list.ensureIndexIsVisible(index);
                }
            }
        }
    }

    private class AddButtonActionListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            JFileChooser fc = new JFileChooser();
            if (lastLocation != null)
            {
                fc.setCurrentDirectory(lastLocation);
            }
            fc.setFileFilter(
                    new FileNameExtensionFilter("Alice class files: *.a2c", "a2c"));
            fc.setMultiSelectionEnabled(true);
            int returnVal = fc.showOpenDialog(null);
            if (returnVal == JFileChooser.APPROVE_OPTION)
            {
                lastLocation = fc.getCurrentDirectory();
                createFileButton.setEnabled(true);
                convertItem.setEnabled(true);
                removeButton.setEnabled(true);
                File[] selectedFiles = fc.getSelectedFiles();
                for (File f : selectedFiles)
                {
                    if (!files.contains(f))
                    {
                        int index = list.getSelectedIndex(); //get selected index
                        if (index == -1)
                        { //no selection, so insert at beginning
                            index = 0;
                        }
                        else
                        {           //add after the selected item
                            index++;
                        }

                        if (listModel.contains(f.getName()))
                        {
                            listModel.insertElementAt(f.getName() + "*", index);
                        }
                        else
                        {
                            listModel.insertElementAt(f.getName(), index);
                        }

                        //Select the new item and make it visible.
                        list.setSelectedIndex(index);
                        list.ensureIndexIsVisible(index);

                        files.add(index, f);
                    }
                }
            }
        }
    }

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            //start the application

            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}
